package org.example.Reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Apple {

    private int price;

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public static void main(String[] args) throws Exception{
        //正常的调用
        Apple apple = new Apple();
        apple.setPrice(5);
        System.out.println("Apple Price:" + apple.getPrice());
        //使用反射调用
        /**
         *  * 通过反射获取对象的一般步骤
         *      * 1.获取类的 Class 对象实例
         *      * 2.根据 Class 对象实例获取 Constructor 对象
         *      * 3.使用 Constructor 对象的 newInstance 方法获取反射类对象
         */
        Class clz = Class.forName("com.chenshuyi.api.Apple");
        Method setPriceMethod = clz.getMethod("setPrice", int.class);
        Constructor appleConstructor = clz.getConstructor();
        Object appleObj = appleConstructor.newInstance();
        setPriceMethod.invoke(appleObj, 14);
        /**
         *   * 而如果要调用某一个方法，则需要经过下面的步骤：
         *      * 1.获取方法的 Method 对象
         *      * 2.利用 invoke 方法调用方法
         */
        Method getPriceMethod = clz.getMethod("getPrice");
        System.out.println("Apple Price:" + getPriceMethod.invoke(appleObj));
        /**
         * 获取反射中的class对象
         */
        //1.Class.forName 静态方法
        Class clz1 = Class.forName("java.lang.String");
        //2.使用 .class 方法
        Class clz2 = String.class;
        //3.使用类对象的 getClass() 方法
        String str = new String("Hello");
        Class clz3 = str.getClass();
        /**
         * 通过反射创建类对象
         */
        //1.通过 Class 对象的 newInstance() 方法
        Class clz4 = Apple.class;
        Apple apple1 = (Apple)clz.newInstance();
        //2.通过 Constructor 对象的 newInstance() 方法
        Class clz5 = Apple.class;
        Constructor constructor = clz.getConstructor();
        Apple apple2 = (Apple)constructor.newInstance();
        //通过 Constructor 对象创建类对象可以选择特定构造方法，而通过 Class 对象则只能使用默认的无参数构造方法。
        // 下面的代码就调用了一个有参数的构造方法进行了类对象的初始化
        Class clz6 = Apple.class;
        Constructor constructor1 = clz.getConstructor(String.class, int.class);
        Apple apple3 = (Apple)constructor.newInstance("红富士", 15);
        /**
         * 通过反射获取类属性、方法、构造器
         */
        //1.通过 Class 对象的 getFields() 方法可以获取 Class 类的属性，但无法获取私有属性
        Class clz7 = Apple.class;
        Field[] fields = clz.getFields();
        for (Field field : fields) {
            System.out.println(field.getName());
            //price
        }
        //2.使用 Class 对象的 getDeclaredFields() 方法则可以获取包括私有属性在内的所有属性
        Class clz8 = Apple.class;
        Field[] fields1 = clz.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field.getName());
            //name
            //price
        }

    }
}